/**
 * 
 */
package browser;

import java.awt.Image;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URI;
import java.net.URLConnection;

import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.JTextPane;

/**
 * Factory-Klasse, um die Swing-Komponenten zu erzeugen, die
 * abhängig von der Art der angegeben Dateien sind.
 * <p>
 * Unterstützt werden:
 * <pre>
 * text/plain
 * text/html (unformatiert)
 * content/unknown (Inhalt wird als Text ausgegebeb)
 * image/gif
 * application/x-shar (Shellskript)
 * application/x-sh (Shellskript)
 * application/x-shellscript (Shellskript)
 * </pre>
 * 
 * @author Pierre Ahrendt und Richard Wilhelm
 * @version 1.0 Jan 11, 2009
 */
public final class ComponentFactory {
    /**
     * wird nicht benötigt, da
     * die Klasse eine Factory-Klasse ist. 
     */
    private ComponentFactory() { }

    /**
     * Erzeugung einer Swing-Komponente mit
     * dem im Parameter übergebenen Text als Inhalt.
     * 
     * @param error Text der in der Komponente ausgegeben werden soll.
     * @return Komponente mit dem angegeben Text als Inhalt.
     */
    public static JComponent createErrorComponent(String error) {
	JTextPane pane = new JTextPane();
	pane.setText(error);
	
	return pane;
    }
    
    /**
     * Erzeugen einer Swing-Komponente in Abhängigkeit
     * des DateiTyps.
     * <p>
     * Unterstützt werden:
     * <pre>
     * text/plain
     * text/html (unformatiert)
     * content/unknown (Inhalt wird als Text ausgegebeb)
     * image/gif
     * application/x-shar (Shellskript)
     * application/x-sh (Shellskript)
     * application/x-shellscript (Shellskript)
     * </pre>
     * 
     * @param uri Angabe zur Resource
     * @return gibt eine Swing-Komponente zurück, die nach
     * 	       Zuordnung des Dateityps erzeugt wird.
     */
    public static JComponent createComponent(URI uri) {
	try {
	    // Verbindung zur Resource
	    URLConnection conn = uri.toURL().openConnection();

	    // Debug-Ausgabe des Content-Types
	    System.out.println(conn.getContentType());

	    if (conn.getContentType().equals("text/plain")
		    || conn.getContentType().equals("text/html")
		    || conn.getContentType().equals("content/unknown")) {
		// Textkomponente erzeugen
		String content = readInput(conn);
		return createTextComponent(content);

	    } else if (conn.getContentType().equals("image/gif")) {
		// Imagekomponente erzeugen
		return createImageComponent(ImageIO.read(conn.getInputStream()));

	    } else if (conn.getContentType().equals("application/x-shar")
		    || conn.getContentType().equals("application/x-sh")
		    || conn.getContentType().equals("application/x-shellscript")) {
		// Shellkomponente erzeugen
		return createShellComponente(conn);

	    } else {
		// Wenn der Dateityp nicht unterstützt wird, dann
		// wird ein Fehler zurückgegeben
		return ComponentFactory.createErrorComponent(uri
			.toASCIIString()
			+ " Dateityp wird nicht unterstützt.");
	    }
	} catch (IOException e) {
	    return ComponentFactory.createErrorComponent(uri.toASCIIString()
		    + " konnte nicht geöffnet werden.");
	}
    }

    /**
     * Erzeugen einer Swing-Komponente, die den Inhalt bzw.
     * das Ergebnis der Berechnung eines angegeben Shell-Skripts
     * ausgibt.
     * <p>
     * Die Ausgabe ist abhängig von der Beantwortung einer
     * Frage des Benutzers.
     * <p>
     * Das Shellscript wird über die angegebene Verbindung in einer
     * temporären Datei gespeichert und dann ausgeführt.
     * 
     * @param conn Verbindung über die das Shellscript geladen
     * 	           werden soll
     * @return Swing-Komponente mit Inhalt des Shellskripts bzw. Ergebnis
     * 		der Berechnung des Swingskripts.
     * @throws IOException wird bei Verbindungsproblemen
     */
    private static JComponent createShellComponente(URLConnection conn) 
    		throws IOException {	    
	// öffnen einen blockierenden Dialogs, die den Benutzer
	// fragt, ob das angegebene Skript ausgeführt werden
	// soll
	int option = JOptionPane.showOptionDialog(
		null, 
		"Es soll ein Shellskript ausgeführt werden.\n"
		+ "Möchten sie dieses ausführen?", 
		"Sicherheitshinweis", 
		JOptionPane.YES_NO_OPTION, 
		JOptionPane.WARNING_MESSAGE, 
		null, 
		null, 
		JOptionPane.NO_OPTION);
	    
	// Wenn die Datei nicht ausgeführt werden soll, wird
	// der Inhalt der Datei ausgegeben
	if (!(option == JOptionPane.YES_OPTION)) {
	    String content = readInput(conn);
	    return createTextComponent(content);
	}
	    
	// erstellen einer temporären Datei script.sh zum Speichern
	// des Inhalts des Skriptes
	File script = File.createTempFile("script", ".sh");
	    
	// Ausführungbit setzen
	script.setExecutable(true);
	    
	// Reader, um den Inhalt der Skriptdatei zu lesen
	BufferedReader in = new BufferedReader(
		new InputStreamReader(conn.getInputStream()));

	// Writer zum Schreiben des Inhalts der Skriptdatei in
	// die temporäre Datei
	BufferedWriter fileOut = new BufferedWriter(
		new OutputStreamWriter(new FileOutputStream(script)));
	    
	// Inhalt der Skriptdatei in temporäre Datei schreiben
	String line;
	while ((line = in.readLine()) != null) {
	    fileOut.append(line + "\n");
	}
	    
	// Shellskript in Datei speichern
	fileOut.flush(); 
		    
	fileOut.close();
	in.close();

	// Skript ausführen
	Process p = Runtime.getRuntime().exec(script.getAbsolutePath());
	    
	// Reader für Ausabe des Prozesses
	in = new BufferedReader(new InputStreamReader(p.getInputStream()));
	    
	// Ergebnis der Berechnung des Prozesses einlesen
	StringBuffer buff = new StringBuffer();
	while ((line = in.readLine()) != null) {
	    buff.append(line + "\n");
	}
	    
	in.close();
	    
	// gestarteten Prozess beenden
	p.destroy();
	    
	return createTextComponent(buff.toString());
    }
    
    /**
     * Erzeugen einer Swing-Komponente, die die angegebene
     * Bildressource darstellt.
     * 
     * @param image das Bild das in der 
     * 		    Swing-Komponente dargestellt werden soll
     * @return gibt die Swingkomponente mit dem Bild als Inhalt zurück
     * @throws IOException wird bei Verbindungsproblemen geworfen
     */
    private static JComponent createImageComponent(Image image) 
    		throws IOException {
	if (image == null) {
	    return ComponentFactory.createErrorComponent(
	    	"Bilddatei konnte nicht geöffnet werden.");
	}
	
	return new ImageComponent(image);
    }
    
    /**
     * Erzeugung eine Swing-Komponente, die
     * als Inhalt den übergebenen Text hat.
     * 
     * @param content Zeichenkette, die in der Swingkomponente 
     * 		      dargestellt werden soll
     * @return Komponente, die die übergebene Zeichenkette enthält
     */
    public static JComponent createTextComponent(String content) {
	JTextArea area = new JTextArea();
	area.setEditable(false);
	
	area.setText(content);
	
	return area;
    }
    
    /**
     * Einlesen der Daten über die Verbindung und 
     * zurückgabe der Zeichenkette.
     * 
     * @param conn Verbindung über die die Daten gelesen werden soll
     * @return Gibt die gesamten Daten in einem String zurück, die
     * 	       über die Verbindung gelesen werden konnte.
     * @throws IOException Wird bei Verbindungsproblemen geworfen.
     */
    private static String readInput(URLConnection conn) 
    		throws IOException {
	BufferedReader in = new BufferedReader(
		new InputStreamReader(conn.getInputStream()));

	StringBuffer buff = new StringBuffer();
	String line;

	while ((line = in.readLine()) != null) {
	    buff.append(line + "\n");
	}
	
	in.close();
	
	return buff.toString();
    }
}
